home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 37 / Amiga Format CD37 (1999-02-16)(Future Publishing)(GB)(Track 1 of 3)[!][issue 1999-03].iso / -screenplay- / shareware / invasionforce / source / cyber1.c < prev    next >
C/C++ Source or Header  |  1999-01-09  |  19KB  |  619 lines

  1. /*
  2. AI Code for Invasion Force - an Explore/Conquer Strategic Wargame
  3. Copyright (C) 1996  Brannen Hough
  4.  
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License
  7. as published by the Free Software Foundation; either version 2
  8. of the License, or any later version.
  9.  
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. */
  19. /*
  20.     cyber1.c -- artificial intelligence module for Empire II
  21.  
  22. */
  23.  
  24. /* This file contains all the routines associated with AI Type #1.
  25. */
  26.  
  27. #include "global.h"
  28.  
  29.  
  30. /***************************************************************
  31. *************** Production Routines  ***************************
  32. ***************************************************************/
  33.  
  34. struct GovNode*  AI1_locate_gov( struct City* metro )
  35. {
  36.     struct GovNode *Gov = (struct GovNode *)GovList.mlh_Head;
  37.     struct GovNode *NewGov = NULL;
  38.  
  39.     for ( ; Gov->gnode.mln_Succ; Gov = (struct GovNode *)Gov->gnode.mln_Succ) {
  40.     if ((Gov->owner == player) && 
  41.         ((Gov->type == GOV_CITY) || (Gov->type == GOV_PORT))
  42.         && (Gov->x == metro->col) && (Gov->y == metro->row)) {
  43.         /* We found the right city governor. */
  44.         return( Gov );
  45.     }  /* End if */
  46.     } /* End for loop */
  47.  
  48.     /* Never found it */
  49.     NewGov = AI1_add_gov( metro );
  50.     /* And, let's set up the governors area of interest */
  51.     AI1_setup_area_of_interest (NewGov);
  52.     return (NewGov);
  53. }
  54.  
  55.  
  56. struct GovNode*  AI1_add_gov( struct City* metro )
  57. {
  58.     struct GovNode *new_gov = AllocVec((int)sizeof(*new_gov),MEMF_CLEAR);
  59.  
  60.     new_gov->x = metro->col;
  61.     new_gov->y = metro->row;
  62.     new_gov->targx = -1;
  63.     new_gov->targy = -1;
  64.     new_gov->searchx = -1;
  65.     new_gov->searchy = -1;
  66.     new_gov->mode = GOV_SEARCH;
  67.     new_gov->flags = 0;
  68.     new_gov->owner = player;
  69.     if (port_cityP(metro))  new_gov->type = GOV_PORT;
  70.     else  new_gov->type = GOV_CITY;
  71.     new_gov->ID = NewGov++;
  72.  
  73.     sprintf (outbuf, "Creating Governor %ld at %ld,%ld",
  74.          new_gov->ID, new_gov->x, new_gov->y);
  75.     DEBUG_AI(outbuf)
  76.     
  77.  
  78.     /* Add the new governor to the list of governors */
  79.     AddTail((struct List *)&GovList,(struct Node *)new_gov);
  80.     return( new_gov );
  81. }
  82.  
  83.  
  84. void  AI1_set_gov_prod (struct City *metro, struct GovNode *CityOwner)
  85. {    
  86.     CityOwner->req.type = RIFLE;
  87.     CityOwner->req.req_gov = CityOwner->ID;
  88.     CityOwner->req.priority = 9;
  89.     /* And we set the city itself to produce this */
  90.     if (metro->unit_type != CityOwner->req.type) {  /*making a new type */
  91.         metro->unit_type = CityOwner->req.type;
  92.         /* Tooling up penalty */
  93.         metro->unit_wip = -1 * wishbook[metro->unit_type].build/5;
  94.         /*sprintf (outbuf, "Tooling Up the city to build a %s",
  95.             UnitString[metro->unit_type]);
  96.         DEBUG_AI(outbuf) */
  97.     }
  98.     /* unit->wip has been set to zero elsewhere.  Don't zero out production
  99.        that has already been started when we haven't changed the type.
  100.        We have enough handicaps as it is. */
  101.     
  102.     return;
  103. }
  104.  
  105.  
  106. void  AI1_play_turn ( int new_units )
  107. {
  108.     int   MaxLooping = 1000;
  109.     /* Here we may want to look around, give out some orders to units,
  110.        and execute orders to units in a loop until we have done all the 
  111.        moves possible for the units.
  112.        */
  113.     AI1_do_all_histograms();
  114.     AI1_give_orders();
  115.     /* We'll add a little failsafe so we don't spend eternity here */
  116.     while( (MaxLooping > 0) && (!AI1_do_unit_actions()) )  MaxLooping--;
  117.     if( MaxLooping <= 0 ) 
  118.     DEBUG_AI("Exitting AI player's turn - out of actions")
  119.     return;
  120. }
  121.  
  122.  
  123. void  AI1_setup_area_of_interest( struct GovNode* Gov )
  124. {
  125.     /* Set up the immediate area of interest */
  126.     Gov->startx = Gov->x - GOVERNOR_RADIUS;
  127.     Gov->starty = Gov->y - GOVERNOR_RADIUS;
  128.     Gov->endx = Gov->x + GOVERNOR_RADIUS;
  129.     Gov->endy = Gov->y + GOVERNOR_RADIUS;
  130.     if (!wrap) {
  131.         if (Gov->startx < 0) Gov->startx = 0;
  132.         if (Gov->starty < 0) Gov->starty = 0;
  133.         if (Gov->endx > width - 1) Gov->endx = width - 1;
  134.         if (Gov->endy > height - 1) Gov->endy = height - 1;
  135.     }
  136.     else {
  137.     if (Gov->startx < 0) Gov->startx += width;
  138.     if (Gov->starty < 0) Gov->starty += height;
  139.     if (Gov->endx > width - 1) Gov->endx -= width;
  140.     if (Gov->endy > height - 1) Gov->endy -= height;
  141.     }
  142.     /* Set up the Extended area of interest */
  143.     Gov->Estartx = Gov->x - EXTENDED_RADIUS;
  144.     Gov->Estarty = Gov->y - EXTENDED_RADIUS;
  145.     Gov->Eendx = Gov->x + EXTENDED_RADIUS;
  146.     Gov->Eendy = Gov->y + EXTENDED_RADIUS;
  147.     if (!wrap) {
  148.         if (Gov->Estartx < 0) Gov->Estartx = 0;
  149.         if (Gov->Estarty < 0) Gov->Estarty = 0;
  150.         if (Gov->Eendx > width - 1) Gov->Eendx = width - 1;
  151.         if (Gov->Eendy > height - 1) Gov->Eendy = height - 1;
  152.     }
  153.     else {
  154.     if (Gov->Estartx < 0) Gov->Estartx += width;
  155.     if (Gov->Estarty < 0) Gov->Estarty += height;
  156.     if (Gov->Eendx > width - 1) Gov->Eendx -= width;
  157.     if (Gov->Eendy > height - 1) Gov->Eendy -= height;
  158.     }
  159.           
  160.     /* sprintf (outbuf,
  161.        "For Gov %ld, Startx:%ld, Starty:%ld, Endx:%ld, Endy:%ld",
  162.        Gov->ID, Gov->startx, Gov->starty, Gov->endx, Gov->endy);
  163.        DEBUG_AI(outbuf)
  164.        */
  165.     return;
  166. }
  167.  
  168.  
  169. void  AI1_do_all_histograms()
  170. {
  171.     struct GovNode *Gov = (struct GovNode *)GovList.mlh_Head;
  172.     /* First we update the picture for all the Governors */
  173.     for ( ; Gov->gnode.mln_Succ; Gov = (struct GovNode *)Gov->gnode.mln_Succ)
  174.     if (Gov->owner == player) {
  175.         AI1_do_one_histogram (Gov);
  176.         AI1_set_gov_mode (Gov);
  177.     }
  178.     /* End for loop */
  179.  
  180. }
  181.  
  182.  
  183. void  AI1_do_one_histogram( struct GovNode* Gov)
  184. {
  185.     int   j, k;
  186.     struct MapIcon *icon = (struct MapIcon *)PLAYER.icons.mlh_Head;
  187.     struct Unit *unit = (struct Unit *)unit_list.mlh_Head;
  188.     
  189.     /* Zero out the histogram for the governor */
  190.     for (j = 0; j < 16; j++)  {
  191.         Gov->hist.TerrainCounts[j] = 0;
  192.         Gov->hist.UnitCounts[j] = 0;
  193.         Gov->hist.EnemyCounts[j] = 0;
  194.     }
  195.     Gov->hist.TotalEUnits = 0;
  196.     Gov->hist.TotalMyUnits = 0;
  197.     Gov->hist.TotalCities = 0;
  198.     Gov->hist.TotalMyCities = 0;
  199.     
  200.     for (j = Gov->startx; j <= Gov->endx ; j++) {
  201.         for (k = Gov->starty; k <= Gov->endy; k++) {
  202.             Gov->hist.TerrainCounts[get(PLAYER.map,j,k)]++;
  203.         } /* End for k */
  204.     } /* End for j */
  205.             
  206.     SetNeutralCity (Gov);
  207.     for (; icon->inode.mln_Succ; icon = (struct MapIcon *)
  208.       icon->inode.mln_Succ) {
  209.         if ((icon->owner != player) && (icon->col >= Gov->Estartx)
  210.             && (icon->col <= Gov->Eendx) && (icon->row >= Gov->Estarty)
  211.             && (icon->row <= Gov->Eendy)) {
  212.         Gov->hist.EnemyCounts[icon->type]++;
  213.         if( (AI5_GetDist( Gov->x, Gov->y, icon->col, icon->row ) <= 6)
  214.         && ( (icon->type == ARMOR) || (icon->type == RIFLE) ||
  215.              (icon->type == AIRCAV) || (icon->type == TRANSPORT) ||
  216.              (icon->type == BOMBER) ) )
  217.             SetCityThreatened(Gov);
  218.         if (icon->type != CITY)  Gov->hist.TotalEUnits++;
  219.         /*sprintf (outbuf, "City %ld found enemy %s at %ld,%ld", 
  220.           Gov->ID, UnitString[icon->type],icon->col, icon->row);
  221.           DEBUG_AI(outbuf)
  222.           */
  223.         if ((icon->owner != 0) && (icon->type == CITY)) 
  224.         ClearNeutralCity (Gov);
  225.         }  /* End if enemy unit detected in our area */
  226.     } /* End for loop for icons */
  227.  
  228.     for (; unit->unode.mln_Succ; unit = (struct Unit *)unit->unode.mln_Succ) {
  229.         if ((unit->owner == player) &&
  230.         (Gov->ID == atoi(unit->name))) {
  231.         Gov->hist.UnitCounts[unit->type]++;
  232.         Gov->hist.TotalMyUnits++;
  233.         }  /* End if we own it and it is owned by this governor */
  234.     } /* End for looking at friendly units */
  235. }
  236.  
  237.  
  238. void  AI1_set_gov_mode( struct GovNode* Gov )
  239. {
  240.     if ((Gov->type == GOV_CITY) || (Gov->type == GOV_PORT)) {
  241.     /* Check to see if we still own our city */
  242.         if (hex_owner(Gov->x, Gov->y) == player) ClearCityTaken(Gov);
  243.         else {
  244.             SetCityTaken(Gov);
  245.             // clear all orders
  246.             AI1_clear_all_orders(Gov);
  247.         }
  248.     }
  249.  
  250.     return;
  251. }
  252.  
  253.  
  254. void  AI1_clear_all_orders( struct GovNode* Gov )
  255. {
  256.     struct Unit* unit = (struct Unit*) unit_list.mlh_Head;
  257.     // Mode has changed - clear all orders for all units owned by gov
  258.     for (; unit->unode.mln_Succ; unit = (struct Unit *)
  259.         unit->unode.mln_Succ) 
  260.             if ((unit->owner == player) && (atoi(unit->name) 
  261.                 == Gov->ID))  clear_orders(unit);
  262.             // End if all that stuff
  263.     // End for loop
  264.     return;
  265. }
  266.  
  267.  
  268. void  AI1_give_orders()
  269. {
  270.     struct  Unit   *unit = (struct Unit *)unit_list.mlh_Head;
  271.     struct GovNode *Gov = NULL;
  272.    
  273.     for (;unit->unode.mln_Succ; unit = (struct Unit *)unit->unode.mln_Succ) 
  274.         if ((unit->owner == player) && (unit->move > 0) && 
  275.             (unit->orders == NULL)) {
  276.             /* No orders yet, let's set some
  277.            Ok, we own the unit, and it has moves left, and has a Governor
  278.            owner, and has no standing orders
  279.            Don't just stand there, do something!
  280.            */
  281.         /* sprintf(outbuf, "Giving initial orders to unit named %s at %ld,%ld", 
  282.                unit->name, unit->col, unit->row);
  283.                DEBUG_AI(outbuf)
  284.            */
  285.             Gov = AI1_FindOwner (unit);
  286.             if (Gov != NULL) {
  287.         if( IsCityTaken( Gov ) ) {
  288.             /* Have the unit move to the city's location */
  289.             ComputerGiveOrders (unit, C_ORDER_GOTO, Gov->x, 
  290.                           Gov->y, -1, -1, -1);
  291.         }
  292.         else {
  293.             /* Have the unit wander randomly */
  294.             ComputerGiveOrders (unit, C_ORDER_RANDOM, -1, -1, 
  295.                           -1,-1, -1);
  296.         }
  297.         }
  298.     } /* end if owner and has moves left */
  299.     /* End For */
  300. }
  301.  
  302. struct GovNode* AI1_FindOwner (struct Unit *unit)
  303. {
  304.     int owner;
  305.     struct GovNode *Gov = (struct GovNode *)GovList.mlh_Head;
  306.     
  307.     if (unit->name == NULL)  {
  308.         DEBUG_AI("Unit name is NULL")
  309.     return (NULL);
  310.     }
  311.  
  312.     owner = atoi(unit->name);
  313.  
  314.     for ( ; Gov->gnode.mln_Succ; Gov = (struct GovNode *)Gov->gnode.mln_Succ)
  315.         /* We have two checks and three fail safes here.
  316.        We must make sure we don't cheat and that the names are
  317.        not NULL (strcmp is not defined in that case)
  318.        */
  319.     if ((Gov->owner == unit->owner) && (Gov->owner == player) 
  320.         && (Gov->ID == owner))
  321.         return (Gov);
  322.     /* End For, If */
  323.     sprintf (outbuf,"Unable to find owning Governor for unit %s", unit->name);
  324.     DEBUG_AI(outbuf)
  325.  
  326.     return (NULL);
  327. }
  328.  
  329.  
  330. void AI1_computer_give_orders(struct Unit *unit,int suborder,short destx,
  331.     short desty,short orgx,short orgy,int etc)
  332. {
  333.    struct Order *order=AllocVec((long)sizeof(*order),MEMF_CLEAR);
  334.  
  335.    clear_orders(unit);
  336.    if (order) {
  337.       order->destx = destx;
  338.       order->desty = desty;
  339.       unit->orders = order;
  340.       order->type = ORDER_NONE;
  341.       if (orgx == -1)  order->orgx = unit->col;
  342.       else  order->orgx = orgx;
  343.       if (orgy == -1)  order->orgy = unit->row;
  344.       else  order->orgy = orgy;
  345.       order->processed = FALSE;
  346.       order->etc = etc;
  347.       order->reserved = suborder;       /* using reserved for computer
  348.                                   orders so I don't tread on the human
  349.                                   player's tokens. */
  350.                                         
  351.       /* This is set up to be in the order they are used most often,
  352.          and set up so that more order types can be added as needed.
  353.      */
  354.       switch (suborder) {
  355.       case C_ORDER_GOTO:
  356.       /* sprintf (outbuf, "%s %s C_ORDER_GOTO from %ld,%ld to %ld,%ld",
  357.          UnitString[unit->type], unit->name, order->orgx, 
  358.          order->orgy, order->destx, order->desty);
  359.          DEBUG_AI(outbuf)
  360.          */
  361.       break;
  362.       case C_ORDER_RANDOM:
  363.       /* Standard stuff only */
  364.       break;
  365.       }
  366.    }
  367. }
  368.  
  369. int  AI1_do_unit_actions()
  370. {
  371.     struct Unit *unit = (struct Unit *)unit_list.mlh_Head;
  372.     struct GovNode *Gov = NULL;
  373.     int         Done = TRUE;
  374.    
  375.  
  376.     for ( ; unit->unode.mln_Succ; unit = (struct Unit *) unit->unode.mln_Succ)
  377.         if ((unit->owner==player) && (unit->move > 0)) {
  378.             /* Skip Sentry units */
  379.             if ((unit->orders == NULL) || 
  380.         (unit->orders->reserved != C_ORDER_SENTRY))   Done = FALSE;
  381.         
  382.         /* Take a look around us and react to enemy units + cities */
  383.         if( AI1_look_around ( unit ) )   return (FALSE);
  384.  
  385.             /* if we have orders, execute them */
  386.             if (unit->orders != NULL) {
  387.                 AI1_execute_standing_order(unit);
  388.                 return (Done);
  389.             }
  390.  
  391.             else {
  392.                 Gov = AI1_FindOwner (unit);
  393.                 if (Gov != NULL) {
  394.             DEBUG_AI("No orders, no enemy around. Huh?")
  395.             unit->move = 0;
  396.             return (Done);
  397.                 } /* End if Gov != NULL */
  398.                 else {
  399.             DEBUG_AI("Cannot find unit owner to ad lib turn")
  400.                     DEBUG_AI("For Now, Forget IT!")
  401.                     sprintf (outbuf, "%s Unit %s at %ld,%ld",
  402.                  UnitString[unit->type], unit->name, unit->col,
  403.                  unit->row);
  404.             DEBUG_AI(outbuf)
  405.                     unit->move = 0;
  406.             return (Done);
  407.                 } /* End else Gov == NULL */
  408.         } /* End else figure something out */
  409.         } /* End if we own unit and it has moves left */
  410.     /* End for loop */
  411.     
  412.     return (Done);
  413. }
  414.  
  415.  
  416. int  AI1_look_around( struct Unit* unit)
  417. {
  418.     int          i, k;
  419.     short        targx, targy;
  420.     struct City* metro;
  421.  
  422.     for (i = 0; i < 6; i++) {
  423.     if (AI1_calc_dir (i, unit->col, unit->row, &targx, &targy) != -1) {
  424.         if ((metro = city_hereP (targx, targy)) && 
  425.         (metro->owner != player)) {
  426.         /* if there is a city here and we don't own it */
  427.         if ((unit->type == RIFLE) || (unit->type == ARMOR)
  428.             || (unit->type == AIRCAV)) {
  429.             /* Go for it! */
  430.             /* DEBUG_AI("Jumping enemy city") */
  431.             (void) move_unit_xy (unit, targx, targy);
  432.             return (1);
  433.         } /* End if can take city */
  434.         } /* End if city here and it ain't ours! */
  435.     } /* End if hex here */
  436.     } /* End For loop */
  437.     for (i = 0; i < 6; i++) {
  438.     if (AI1_calc_dir (i, unit->col, unit->row, &targx, &targy) != -1) {
  439.         if (((k = hex_owner(targx,targy)) > 0)&&(k!=player)) {
  440.         /* Somebody there - for now just jump 'em */
  441.         /*DEBUG_AI("Jumping enemy unit") */
  442.         (void) move_unit_xy (unit, targx, targy);
  443.         return (1);
  444.         }  /* End if bad guy here */
  445.     } /* End if hex here */
  446.     } /* End for loop */
  447.     return (0);
  448. }
  449.  
  450.  
  451. /* This routine calculates the new coordinates resulting from heading in
  452.    a particular direction from given coordinates.  Returns -1 for not
  453.    possible, and a 1 for OK.
  454.    */
  455. int AI1_calc_dir (enum Direction dir, short orgx, short orgy, 
  456. short *x, short *y)
  457. {
  458.    int  targx = orgx;
  459.    int  targy = orgy;
  460.    
  461.    switch (dir) {
  462.       case EAST:
  463.          targx++;
  464.          break;
  465.       case WEST:
  466.          targx--;
  467.          break;
  468.       case NORTHEAST:
  469.          targy--;
  470.          if (orgy%2) /* odd number */
  471.             targx++;
  472.          break;
  473.       case NORTHWEST:
  474.          targy--;
  475.          if (!(orgy%2)) /* even number */
  476.             targx--;
  477.          break;
  478.       case SOUTHEAST:
  479.          targy++;
  480.          if (orgy%2) /* odd number */
  481.             targx++;
  482.          break;
  483.       case SOUTHWEST:
  484.          targy++;
  485.          if (!(orgy%2)) /* even number */
  486.             targx--;
  487.          break;
  488.       default:
  489.             return (-1);
  490.     }
  491.  
  492.    /* correct values for wrap, if it's active */
  493.    if (wrap) {
  494.       if (targx<0)
  495.          targx += width;
  496.       if (targx>=width)
  497.          targx -= width;
  498.       if (targy<0)
  499.          targy += height;
  500.       if (targy>=height)
  501.          targy -= height;
  502.    }
  503.  
  504.    /* he certainly can't move off the map! */
  505.    if (targx<0 || targx>=width || targy<0 || targy>=height) {
  506.         DEBUG_AI("Moving Off Map")
  507.            return(-1);
  508.    }
  509.  
  510.    *x = targx;
  511.    *y = targy;
  512.    
  513.    return (1);
  514. }
  515.  
  516. void  AI1_execute_standing_order( struct Unit* unit)
  517. {
  518.     int        result;
  519.  
  520.     if ((unit->orders == NULL) || (unit->orders->type != ORDER_NONE)) {
  521.     DEBUG_AI("Big problem in execute_standing_order - no orders!")
  522.     sprintf (outbuf, "%s %s has no standing orders to execute - aborting",
  523.          UnitString[unit->type], unit->name);
  524.     DEBUG_AI(outbuf)
  525.     return;
  526.     }
  527.     
  528.     switch (unit->orders->reserved) {
  529.         case  C_ORDER_GOTO:
  530.             result = AI1_command_headto(unit);
  531.             if (result < 0) clear_orders(unit);   /* problem */
  532.             if (result == 0) clear_orders(unit);  /* done */
  533.             break;
  534.         case  C_ORDER_RANDOM:
  535.             AI1_command_random(unit);
  536.             break;
  537.         default:
  538.             DEBUG_AI("Unknown command type found in execute_standing_order!")
  539.             break;
  540.     }
  541.     return;
  542. }
  543.  
  544.  
  545. void  AI1_command_random( struct Unit* unit )
  546. {
  547.     enum    Direction Randdir = RangeRand(6L);
  548.     int     i;
  549.  
  550.     /* About as simple as it gets! We'll try 10 times to make a valid move.*/
  551.     for( i=0; i < 10; i++ ) {
  552.         if(  move_unit_dir(unit, Randdir) != -1 )  return;
  553.         Randdir = RangeRand(6L);
  554.     }
  555.     return;
  556. }
  557.  
  558.  
  559. int   AI1_command_headto( struct Unit* unit )
  560. {
  561.     int  i, j;
  562.     int  result;
  563.  
  564.     /* Check to see if we have arrived */
  565.     if ((unit->col == unit->orders->destx) && 
  566.         (unit->row == unit->orders->desty))  {
  567.         /* We have arrived! */
  568.         /* DEBUG_AI("We have arrived!") */
  569.         return (0);
  570.     }
  571.  
  572.     /* Select the correct direction to look in */
  573.     i = 0;
  574.     if (unit->orders->destx - unit->col <= 0)  i = 3;
  575.     if( (unit->orders->destx == unit->col) && (unit->col%2 == 0) )  i = 0;
  576.     if (unit->orders->desty - unit->row < 0)  i += 1;
  577.     if (unit->orders->desty == unit->row)     i += 2;
  578.     
  579.     /* Let's move in the three most likely directions only */
  580.     for (j = 0; j < 3; j++) {
  581.         /* -1 is the only return value where a move might still be possible
  582.             We must be sure we only do ONE move - ever */
  583.         if ((result = move_unit_dir(unit, DirArray[i][j])) != -1) {
  584.             /*sprintf (outbuf, "Moved %s, result %ld", 
  585.               DirString[DirArray[i][j]], result);
  586.               DEBUG_AI(outbuf)
  587.               */
  588.             if( (result > -3) && (unit->orders) ) {
  589.                 /* We didn't die in an attack, and we didn't crash, so 
  590.                 let's check for destination again
  591.                 */
  592.                 /*DEBUG_AI("Checking for Destination") */
  593.                if ((unit->col == unit->orders->destx) && 
  594.                    (unit->row == unit->orders->desty))  {
  595.                    /* We have arrived! */
  596.                    /* DEBUG_AI("We have arrived!") */
  597.                    return (0);
  598.                }
  599.                unit->orders->etc--;
  600.                if (unit->orders->etc < 0)  {
  601.                    DEBUG_AI("Watchdog on HeadTo ran out")
  602.                    return (-2);
  603.                }
  604.             }
  605.             return (1);
  606.         }
  607.         else {
  608.             sprintf (outbuf, "%s %s Tried to move in direction %s, result %ld",
  609.                 UnitString[unit->type], unit->name, DirString[DirArray[i][j]], 
  610.                 result);
  611.             DEBUG_AI(outbuf)
  612.         }
  613.     } /* End for loop */
  614.     
  615.     /* No luck at all */
  616.     DEBUG_AI ("Cannot move towards - clearing orders")
  617.     return (-1);
  618. }
  619.